package com.efivestar.idm.api.service.lock.protocol.handler;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.efivestar.idm.api.common.Cons;
import com.efivestar.idm.api.domain.CameraDomain;
import com.efivestar.idm.api.domain.EventDomain;
import com.efivestar.idm.api.domain.Lock2UserDomain;
import com.efivestar.idm.api.domain.WeixinJoinDeviceDomain;
import com.efivestar.idm.api.exception.ErrorParamException;
import com.efivestar.idm.api.repository.CameraMapper;
import com.efivestar.idm.api.repository.EventMapper;
import com.efivestar.idm.api.repository.WeixinJoinDeviceMapper;
import com.efivestar.idm.api.service.DeviceService;
import com.efivestar.idm.api.service.WeixinService;
import com.efivestar.idm.api.service.dto.PowerDto;
import com.efivestar.idm.api.util.ByteUtils;
import com.efivestar.idm.api.util.weixin.WeixinApi;
import com.efivestar.idm.api.util.weixin.bean.TemplateMessage;

import io.netty.buffer.ByteBuf;
import tk.mybatis.mapper.entity.Example;

/**
 * 开门.
 */
@Service
public class OpenDoorLockProtocolHandler extends AbstractLockProtocolHandler{

    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private EventMapper mapper;


    @Autowired
    private DeviceService deviceService;

    @Autowired
    private WeixinService weixinService;


    @Autowired
    private WeixinJoinDeviceMapper weixinJoinDeviceMapper;

    @Autowired
    private CameraMapper cameraMapper;

    @Autowired
    private WeixinApi weixinApi;

    @Value("${weixin.warningTemplateId:jZt8KiYA6wsIkVqNqL12GAfVnzZftFD895bEva0zPLA}")
    private String warningWeixinTemplateId;

    @Value("${service.domain:51ai.cc}")
    private String domain;



    @Override
    protected int getDataLenthWithoutDeviceId() {
        return 5;
    }

    /**
     * @param buf
     * @param lockId
     * @return
     */
    @Override
    public byte[] handleData(ByteBuf buf, String lockId) {
        int length = buf.readableBytes();
        //跳过指令码，不读取
        buf.skipBytes(1);
//        读取电量字节
        byte powerBt = buf.readByte();
        PowerDto power = ByteUtils.getPower(powerBt);
//        读取开门类型字节
        byte eventType = buf.readByte();
//        读取编码
        ByteBuf codeBf = buf.readBytes(2);
        String userCode = ByteUtils.getUserCode(codeBf);
        //读取imei(设备编号)
        // String lockId = String.valueOf(buf.readCharSequence(length - 5, Charset.forName("utf-8")));
        //设置设备的电量和更新时间
        deviceService.updatePower(lockId, power.getPowerPercent());
        EventDomain event = EventDomain.builder().deviceId(lockId).eventType(Cons.OPEN_DOOR_EVENT_TYPE).subEventType(getEventType(eventType)).content(userCode).createTime(new Date()).build();
        mapper.insert(event);
        //获取设备的所有用户.
        List<Lock2UserDomain> lock2Users = weixinService.queryLockUsersByLockId(lockId);
        //当前用户在用户列表中
        Lock2UserDomain lockUser = getLockUser(lock2Users, eventType, userCode);
        if (lockUser != null) {
            //用户是劫持用户
            if ( lockUser.isHijackStatus()) {
                sendNotification(lockId, event.getId(),true, getEventType(eventType), lockUser);
            } else {
                sendNotification(lockId, event.getId(),false, getEventType(eventType), lockUser);
            }
        } else {
//            当前用户不在用户列表，所以只能发送用户code
            sendNotification(lockId, event.getId(),getEventType(eventType), userCode);
            logger.error("用户不存在,开门时设备id:{},用户code:{}, 事件类型:{}, ", new Object[]{lockId, userCode, eventType});
        }

        return ByteUtils.hexToBytes("00");
    }


    /**
     * 发送通知信息.
     * 如果是劫持，则信息内容为红色， 并且可以查看摄像头.否则就是普通的信息，点击之后可以跳转到事件列表界面.
     * @param deviceId
     * @param eventId 事件id.
     * @param isHijack
     */
    private void sendNotification(String deviceId, Long eventId, boolean isHijack, int eventType, Lock2UserDomain hijack ) {
        //发送微信通知.
        String now = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        List<WeixinJoinDeviceDomain> weixinJoinDeviceDomains = weixinJoinDeviceMapper.selectByExample(generateUserJoinDeviceExample(deviceId));
        for (WeixinJoinDeviceDomain weixinJoinDeviceDomain : weixinJoinDeviceDomains) {
            String toUser = weixinJoinDeviceDomain.getOpenId();
            String eventTypeName = getEventTypeName(eventType);
            Map map = new HashMap<>();
            if (isHijack) {
                map.put("first", TemplateMessage.builder().value("开门通知").color("#74F192").build());
                map.put("keyword1", TemplateMessage.builder().value("用户 "+ (StringUtils.isEmpty(hijack.getUserName()) ? hijack.getUserCode(): hijack.getUserName()) + " 遭到劫持").color("#F00").build());
                map.put("keyword2", TemplateMessage.builder().value(now).color("#F00").build());
                String cameraUrl = null;
                if (StringUtils.isNotEmpty(weixinJoinDeviceDomain.getCameraId())) {
                    CameraDomain cameraDomain = CameraDomain.builder().cameraId(weixinJoinDeviceDomain.getCameraId()).build();
                    CameraDomain dbCamera = cameraMapper.selectByPrimaryKey(cameraDomain);
                    if (dbCamera != null && StringUtils.isNotEmpty(dbCamera.getUrl())) {
                        cameraUrl = "http://" + domain + "/cameraPage";
                        map.put("remark", TemplateMessage.builder().value("点击查看摄像头").color("#F00").build());
                    } else {
                        logger.error("摄像头:{},不存在对应的视频连接。但是关系表中存在关联关系", weixinJoinDeviceDomain.getCameraId());
                    }
                }
                boolean result = weixinApi.sendTemplateMessage(toUser, warningWeixinTemplateId, cameraUrl,
                        map, "#F00");
                logger.info("开门推送，智能锁id:{}, toUser:{}, 结果: {}", new Object[]{deviceId, toUser, result});
            } else {
                map.put("first", TemplateMessage.builder().value("开门通知").color("#74F192").build());
                map.put("keyword1", TemplateMessage.builder().value("用户 "+ (StringUtils.isEmpty(hijack.getUserName()) ? hijack.getUserCode(): hijack.getUserName()) + "["+ eventTypeName +"] 回家了").build());
                map.put("keyword2", TemplateMessage.builder().value(now).build());
                String eventDetail = "http://" + domain + "/deviceEvent?eventId=" + eventId;
                boolean result = weixinApi.sendTemplateMessage(toUser, warningWeixinTemplateId, eventDetail,
                        map, null);
                logger.info("开门推送，智能锁id:{}, toUser:{}, 结果： {}", new Object[]{deviceId, toUser, result});
            }
        }
    }


    /**
     * 发送通知信息.
     * 如果是劫持，则信息内容为红色， 并且可以查看摄像头.否则就是普通的信息，点击之后可以跳转到事件列表界面.
     * @param deviceId
     * @param eventId 事件id.
     */
    private void sendNotification(String deviceId, Long eventId, int eventType, String userCode ) {
        //发送微信通知.
        String now = DateFormatUtils.format(new Date(), "yyyy-MM-dd HH:mm:ss");
        List<WeixinJoinDeviceDomain> weixinJoinDeviceDomains = weixinJoinDeviceMapper.selectByExample(generateUserJoinDeviceExample(deviceId));
        for (WeixinJoinDeviceDomain weixinJoinDeviceDomain : weixinJoinDeviceDomains) {
            String toUser = weixinJoinDeviceDomain.getOpenId();
            Map map = new HashMap<>();
            map.put("first", TemplateMessage.builder().value("开门通知").color("#74F192").build());
            String eventTypeName = getEventTypeName(eventType);
            map.put("keyword1", TemplateMessage.builder().value("用户 "+ userCode + "(" + eventTypeName +") 回家了").build());
            map.put("keyword2", TemplateMessage.builder().value(now).build());
            String eventDetail = "http://" + domain + "/deviceEvent?eventId=" + eventId;
            boolean result = weixinApi.sendTemplateMessage(toUser, warningWeixinTemplateId, eventDetail,
                    map, null);
            logger.info("开门推送，智能锁id:{}, toUser:{}, 结果： {}", new Object[]{deviceId, toUser, result});
        }
    }


    private String getEventTypeName(int eventType) {
        switch (eventType) {
            case Cons.OPEN_DOOR_BY_FIGURE_EVENT:
                return "指纹";
            case Cons.OPEN_DOOR_BY_PASSWORD_EVENT:
                return "密码";
            case Cons.OPEN_DOOR_BY_CARD_EVENT:
                return "卡";
            case Cons.OPEN_DOOR_BY_KEY_EVENT:
                return "钥匙";
            case Cons.OPEN_DOOR_BY_REMOTE_CONTROL_EVENT:
                return "遥控";
        }
        return "";
    }
    private Example generateUserJoinDeviceExample(String deviceId) {
        Example example = new Example(WeixinJoinDeviceDomain.class);
        Example.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotEmpty(deviceId)){
            criteria.andEqualTo("deviceId", deviceId);
        }
        return example;
    }



    private Lock2UserDomain getLockUser(List<Lock2UserDomain> lock2Users, int type, String userCode) {
        if (lock2Users != null) {
            List<Lock2UserDomain> hiJackUsers = lock2Users.stream().filter(d -> (d.getType().intValue() == type && d.getUserCode().equalsIgnoreCase(userCode))).collect(Collectors.toList());
            return hiJackUsers.size() > 0 ? hiJackUsers.get(0): null;
        }
        return null;
    }


    /**
     * 获取开门的子事件类型.
     * @param eventTypeBt
     * @return
     */
    private int getEventType(byte eventTypeBt) {
        String eventType = ByteUtils.bytes2hex(eventTypeBt);
        switch (eventType) {
            case "00":
                return Cons.OPEN_DOOR_BY_FIGURE_EVENT;
            case "01":
                return Cons.OPEN_DOOR_BY_PASSWORD_EVENT;
            case "02":
                return Cons.OPEN_DOOR_BY_CARD_EVENT;
            case "03":
                return Cons.OPEN_DOOR_BY_KEY_EVENT;
            case "04":
                return Cons.OPEN_DOOR_BY_REMOTE_CONTROL_EVENT;
        }
        throw new ErrorParamException();
    }


    public static byte[] subBytes(byte[] src, int begin, int count) {
        byte[] bs = new byte[count];
        System.arraycopy(src, begin, bs, 0, count);
        return bs;
    }

    @Override
    public String udpHead(){
        return Cons.UDP_HEAD_EF01;
    }

    @Override
    public String udpCommand(){
        return Cons.UDP_COMMAND_OPEN_DOOR;
    }


    public static void main(String[] args) {
//        ByteUtils.hexToBytes("c3")

        System.out.println(Integer.parseUnsignedInt("c3", 16));
    }

}






